#include "../userprog/syscall.h"
/*/======== Concession Clerk Function ========*/
void main()
{
	int myIndex;
	
/*Shared Data*/
int latestIndexLock;
int latestIndex;
int latestIndexCondition;
int ccStateLock;
int ccState;
int NUM_CONCESSION_CLERKS;
int CLERK_AVAILABLE;
int CLERK_ON_BREAK;
int CLERK_BUSY;
int ccInteractionCondition;
int ccInteractionLock;
int ccBreakLock;
int ccBreakCondition;
int numPopcornDesired;
int numSodaDesired;
int POPCORN_PRICE;
int SODA_PRICE;
int profitLock;
int totalPopcornSold;
int totalSodaSold;
int ccBreakStopLock;
int ccBreakStopCondition;
int ccLineManager;
int ccLineLength;
int ccLineCondition;
int PRINT_DEBUG_MESSAGES;
int PRINT_OUTPUT_MESSAGES;

/*Acquire Shared Data*/
NUM_CONCESSION_CLERKS = CreateMV(1,"NUM_CONCESSION_CLERKS",21);
latestIndexLock = CreateLock("latestIndexLock", 15);
latestIndex = CreateMV(1,"latestIndex", 11);
latestIndexCondition = CreateCondition("latestIndexCondition",20);
ccStateLock = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccStateLock",11);
ccState = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccState",7);
CLERK_AVAILABLE = CreateMV(1,"CLERK_AVAILABLE",15);
CLERK_ON_BREAK = CreateMV(1,"CLERK_ON_BREAK",14);
CLERK_BUSY = CreateMV(1,"CLERK_BUSY",10);
ccInteractionCondition = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccInteractionCondition",22);
ccInteractionLock = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccInteractionLock",17);
ccBreakLock = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccBreakLock",11);
ccBreakCondition = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccBreakCondition",16);
numPopcornDesired = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"numPopcornDesired",17);
numSodaDesired = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"numSodaDesired", 14);
POPCORN_PRICE = CreateMV(1,"POPCORN_PRICE",13);
SODA_PRICE = CreateMV(1,"SODA_PRICE",10);
profitLock = CreateLock("profitLock",10);
totalPopcornSold = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"totalPopcornSold",16);
totalSodaSold = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"totalSodaSold",13);
ccBreakStopLock = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccBreakStopLock",15);
ccBreakStopCondition = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccBreakStopCondition",20);
ccLineManager = CreateLock("ccLineManager",13);
ccLineLength = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccLineLength",12);
ccLineCondition = CreateMV(GetMV(NUM_CONCESSION_CLERKS,0),"ccLineCondition",15);
PRINT_DEBUG_MESSAGES = CreateMV(1,"PRINT_DEBUG_MESSAGES",20);
PRINT_OUTPUT_MESSAGES = CreateMV(1,"PRINT_OUTPUT_MESSAGES", 21);
	
	
	AcquireLock(latestIndexLock);
	myIndex = GetMV(latestIndex,0);
	SignalCondition(latestIndexCondition, latestIndexLock);
	ReleaseLock(latestIndexLock);


	if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: created\n", 29, 1, myIndex);
	AcquireLock(GetMV(ccStateLock,myIndex));
	SetMV(ccState,myIndex,GetMV(CLERK_AVAILABLE,0));
	
	while(1)
	{
		/*/Wait for Customer's food order*/
		ccInteractionWaitLabel:
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: waiting for next Customer\n", 47, 1, myIndex);
		WaitCondition(GetMV(ccInteractionCondition,myIndex), GetMV(ccInteractionLock,myIndex));
		
		if(GetMV(ccState,myIndex) == GetMV(CLERK_ON_BREAK,0))
		{
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: going on break...\n", 39, 1, myIndex);
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring ccBreakLock %d\n", 46, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(ccBreakLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: signalling ccInteractionLock %d\n", 53, 2, myIndex*100 + myIndex);
			SignalCondition(GetMV(ccInteractionCondition,myIndex), GetMV(ccInteractionLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: releasing ccInteractionLock %d\n", 52, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(ccInteractionLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: waiting ccBreakLock %d\n", 44, 2, myIndex*100 + myIndex);
			WaitCondition(GetMV(ccBreakCondition,myIndex), GetMV(ccBreakLock,myIndex));
			goto ccBreakLabel;
		}
		
		/*/After getting signalled by Customer with food order*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring ccInteractionLock %d\n", 52, 2, myIndex*100 + myIndex);
		AcquireLock(GetMV(ccInteractionLock,myIndex));
		
		SetMV(ccState,myIndex,GetMV(CLERK_BUSY,0));
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: processing %d popcorn and %d soda\n", 55, 3, myIndex*10000 + GetMV(numPopcornDesired,myIndex)*100 + GetMV(numSodaDesired,myIndex));
		if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("ConcessionClerk %d has an order for %d popcorn and %d soda.  The cost is %d.\n", 78, 4, 
				myIndex*1000000 + GetMV(numPopcornDesired,myIndex)*10000 + GetMV(numSodaDesired,myIndex)*100 + GetMV(numPopcornDesired,myIndex) * GetMV(POPCORN_PRICE,0) + GetMV(numSodaDesired,myIndex) * GetMV(SODA_PRICE,0));
		
		/*/Process food order and add to total*/
		AcquireLock(profitLock);
		SetMV(totalPopcornSold,myIndex, GetMV(totalPopcornSold,myIndex) + GetMV(numPopcornDesired,myIndex));
		SetMV(totalSodaSold,myIndex, GetMV(totalSodaSold,myIndex) + GetMV(numSodaDesired,myIndex));
		ReleaseLock(profitLock);
		
		/*/Signal Customer to complete transaction*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: signalling Customer with %d popcorn and %d soda\n", 69, 3, myIndex*10000 + GetMV(numPopcornDesired,myIndex)*100 + GetMV(numSodaDesired,myIndex));
		SignalCondition(GetMV(ccInteractionCondition,myIndex), GetMV(ccInteractionLock,myIndex));
		
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: waiting for Customer to receive food\n", 58, 1, myIndex);
		WaitCondition(GetMV(ccInteractionCondition,myIndex), GetMV(ccInteractionLock,myIndex));
		
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: Customer received food succesfully\n", 56, 1, myIndex);
		
		/*/Release state for manager to edit*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: releasing ccStateLock %d\n", 46, 2, myIndex*100 + myIndex);
		ReleaseLock(GetMV(ccStateLock,myIndex));
		
		/*/Finished dealing with customer, perhaps go on break*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: releasing ccStateLock %d\n", 46, 2, myIndex*100 + myIndex);
		AcquireLock(GetMV(ccStateLock,myIndex));
		if(GetMV(ccState,myIndex) == GetMV(CLERK_ON_BREAK,0))
		{
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("ConcessionClerk %d is going on break.\n", 39, 1, myIndex);
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: signalling Manager that I am going on break\n", 65, 1, myIndex);
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring ccBreakStopLock %d\n", 50, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(ccBreakStopLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring ccBreakLock %d\n", 46, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(ccBreakLock,myIndex));
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: signalling ccBreakStopLock %d\n", 51, 2, myIndex*100 + myIndex);
			SignalCondition(GetMV(ccBreakStopCondition,myIndex), GetMV(ccBreakStopLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: release ccBreakStopLock %d\n", 48, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(ccBreakStopLock,myIndex));
			
			ccBreakLabel:
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: releasing ccStateLock %d\n", 46, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(ccStateLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: waiting ccBreakLock %d\n", 44, 2, myIndex*100 + myIndex);
			WaitCondition(GetMV(ccBreakCondition,myIndex), GetMV(ccBreakLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring ccStateLock %d\n", 46, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(ccStateLock,myIndex));
			
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("ConcessionClerk %d is coming off break.\n", 41, 1, myIndex);
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: returning from break\n", 42, 1, myIndex);
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring ccInteractionLock %d\n", 52, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(ccInteractionLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: signalling ccBreakLock %d\n", 47, 2, myIndex*100 + myIndex);
			SignalCondition(GetMV(ccBreakCondition,myIndex), GetMV(ccBreakLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: releasing ccBreakLock %d\n", 46, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(ccBreakLock,myIndex));
			goto ccInteractionWaitLabel;
		}
		
		/*/Lock down lines before accepting next Customer*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: acquiring Lock for Customer search\n", 56, 1, myIndex);
		AcquireLock(ccLineManager);
		AcquireLock(GetMV(ccInteractionLock,myIndex));
		
		/*/Check for customers in line*/
		if(GetMV(ccLineLength,myIndex) > 0)
		{
			/*/I have a customer in line, set myself to busy and decrement line length*/
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("ConcessionClerk %d has a line length %d and is signalling a customer.\n", 71, 2, myIndex*100 + GetMV(ccLineLength,myIndex));
			
			SetMV(ccState,myIndex, GetMV(CLERK_BUSY,0));
			SetMV(ccLineLength,myIndex, GetMV(ccLineLength,myIndex) - 1);
			
			/*/Wake up 1 customer*/
			SignalCondition(GetMV(ccLineCondition,myIndex), ccLineManager);
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: woke up next Customer\n", 43, 1, myIndex);
		}
		else
		{
			/*/No one in my line, set myself to available*/
			SetMV(ccState,myIndex, GetMV(CLERK_AVAILABLE,0));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: no Customers in line\n", 42, 1, myIndex);
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("ConcessionClerk %d has no one in line.  I am available for a customer.\n", 72, 1, myIndex);
		}
		
		/*/Release and allow other Customers to search lines*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("ConcessionClerk %d: releasing Lock for Customer search\n", 56, 1, myIndex);
		ReleaseLock(ccLineManager);
	}
}
